using System;
using System.CodeDom .Compiler ;
using System.CodeDom;
using EnvDTE;
using Extensibility;
using System.Collections ;
using System.Text ;
using System.Xml ;
using System.Text .RegularExpressions ;
namespace AopDotNet
{
	namespace CodeModelXMLTreeBuilder
	{
		public class CodeInspector
		{
			static string identifierPattern=@"(?<identifier>\w\w*)";
	
			/// <summary>
			/// get the base classes statment (inheerits sss)of the given class
			/// </summary>
			/// <param name="className">class name</param>
			/// <param name="strClass">code of the class</param>
			/// <param name="codeGen"></param>
			/// <returns></returns>
			static public string GetBases (string className ,string strClass,ICodeGenerator codeGen)
			{
				string basesPattern=LanguageEngine.PrepareBasesPattern(codeGen);
				basesPattern=basesPattern.Replace ("+","($$)");
				CodeTypeDeclaration t=new CodeTypeDeclaration (@"\s*"+className +@"\s*");
				t.IsClass =true;
				t.TypeAttributes=0;
				//t.BaseTypes.Add ( basesPattern);
				t.Members .Add (new CodeSnippetTypeMember (@"(?<body>(\s|\w|.)*)"));
			
				StringBuilder strPattern=new StringBuilder(LanguageEngine .GenerateCodeFromType  (t,codeGen));
				//strPattern.Replace ("{","[{]");
				//strPattern.Replace ("}","[}]");
				strPattern.Insert (strPattern.ToString ().IndexOf ("\\s*"+className+"\\s*")+className.Length +6,basesPattern);	
				strPattern.Replace ("($$)","+");
		
				//first mark the necessary spaces
				strPattern=new StringBuilder(Regex.Replace (strPattern.ToString (),@"(?<first>\w\w*)\s+(?<second>\w\w*)",new MatchEvaluator (CodeInspector.MatchEval)));
		
				//then remove the un necessary ones
				strPattern.Replace ("\r\n","");
				strPattern.Replace (" ","");
		
				System.Text .RegularExpressions.Match m=null;
				string patt=@"(?<typeattributes>(\s|\w)*)"+strPattern.ToString ();
				try
				{
					m=System.Text .RegularExpressions .Regex .Match (strClass,patt);
				}
				catch (Exception ex)
				{
					return "";
				}
				if (m.Success )
				{
					return m.Groups["bases"].Value;
				}
				return "";
			}

			static public string GetBases (CodeClass cClass,ICodeGenerator codeGen,Editor.EditingMonitor editMon)
			{/*REMF*/
				EditPoint st=cClass.StartPoint .CreateEditPoint ();
				editMon.UpdateEditPoint (ref st);
				EditPoint end=cClass.GetEndPoint (vsCMPart .vsCMPartWhole ).CreateEditPoint ();
				editMon.UpdateEditPoint (ref end);
				string strClass=st.GetText (end);

				return GetBases(cClass.Name ,strClass,codeGen);
			}


			/// <summary>
			/// returns whether the given class is derived form one of the classes specified by <paramref cref="bases"/>
			/// </summary>
			/// <param name="cClass"></param>
			/// <param name="bases"></param>
			/// <param name="codeGen"></param>
			/// <returns></returns>
			static public bool IsDerivedFrom (CodeClass cClass,string [] bases,ICodeGenerator codeGen,Editor.EditingMonitor monitor)
			{
				string strbases=GetBases(cClass,codeGen,monitor);
				for (int i=0;i<bases.Length ;i++)
				{
					string [] arr=System.Text .RegularExpressions .Regex .Split (strbases,@"(\W|^)"+bases[i]+@"(\W|$)");
					if ((arr.Length >=2)||((arr.Length ==1)&&(arr[0]==bases[i])))
						return true;
				}

				return false;
			}
	
			/// <summary>
			/// takes a bases statement <code >Inherits Object Implements ISerializable</code> and return the names
			/// of the base (Object,ISerializable)
			/// </summary>
			/// <param name="strBases"></param>
			/// <returns></returns>
			static public ArrayList ExtractBasesNames(string strBases,ICodeGenerator codeGen)
			{
				string[] keywords=LanguageEngine.KeywordsAndDelimetersInClassDeclarationWithBases(codeGen );
				for (int i=0;i<keywords.Length ;i++)
				{
					if (keywords[i].Length !=0)
						strBases=strBases.Replace (keywords[i]," ");
				}
				ArrayList  bases=new ArrayList (10);
				foreach (string s in Regex .Split (strBases,@"[\s]+"))
				{
					if (s.Length >0)
						bases.Add (s);
				}
				return bases;
			}

			/// <summary>
			/// a delegate that is called each time a match is evaluated in a replace operation
			/// <see cref=" PartitionClass"/>
			/// </summary>
			/// <param name="m"></param>
			/// <returns></returns>
			static string MatchEval(Match m)
			{
				return m.Groups ["first"].Value +@"\s+"+m.Groups ["second"].Value ;
			}

	
			/// <summary>
			/// parse the code of the given class and returns the base classes statment ,body,attributes parts
			/// </summary>
			/// <param name="className">name of the class to parse</param>
			/// <param name="strClass">code of the class</param>
			/// <param name="resBases">the base classes of the class</param>
			/// <param name="resBody">the body of the class</param>
			/// <param name="resAtt">the type attributes of the class</param>
			/// <param name="codeGen"></param>
			static public  void PartitionClass (string className,string strClass,ref string resBases,ref string resBody,ref string resAtt,ICodeGenerator codeGen)
			{
				//generate a pattern of the class
				bool flag=true;
				string basesPattern=LanguageEngine.PrepareBasesPattern(codeGen);
				basesPattern=basesPattern.Replace ("+","($$)");

				CodeTypeDeclaration t=new CodeTypeDeclaration (@"\s*"+className +@"\s*");
				//t.BaseTypes.Add ( @"\s*"+basesPattern+@"\s*");
				LL:
					t.IsClass =true;
				t.TypeAttributes=0;
				t.Members .Add (new CodeSnippetTypeMember (@"(?<body>(\s|\w|.)*)"));
			
				StringBuilder strPattern=new StringBuilder(LanguageEngine .GenerateCodeFromType  (t,codeGen));
			
				if (flag==true)
				{
					//insert the bases after the name of the class
					strPattern.Insert (strPattern.ToString ().IndexOf ("\\s*"+className+"\\s*")+className.Length +6,basesPattern);
				}

				strPattern.Replace ("($$)","+");

				//first mark the necessary spaces
				strPattern=new StringBuilder(Regex.Replace (strPattern.ToString (),@"(?<first>\w\w*)\s+(?<second>\w\w*)",new MatchEvaluator (CodeInspector.MatchEval)));
		
				//then remove the un necessary ones
				strPattern.Replace ("\r\n","");
				strPattern.Replace (" ","");
		
				string patt=@"(?<typeattributes>(\s|\w)*)"+strPattern.ToString ();
				try
				{
					Match m=System.Text .RegularExpressions .Regex .Match (strClass,patt,RegexOptions.IgnoreCase );
					if (m.Success )
					{
						if (flag==true)
							resBases= m.Groups["bases"].Value;
						else
							resBases="";
						resBody= m.Groups["body"].Value;
						resAtt= m.Groups["typeattributes"].Value;
					}
					else
					{   
						//usually failed because the class doesn,t have base classes
						//so create another class that don't have base classes
						if (flag==true)
						{
							t=new CodeTypeDeclaration (@"\s*"+className +@"\s*");
							flag=false;
							goto LL;
						}
					}
				}
				catch (Exception ex)
				{
					/*Error Handling*/
				}
			}

		}
	}
}